@zhin.js/adapter-qq 5.0.1 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/README.md +52 -408
- package/adapters/qq.ts +45 -0
- package/agent/tools/add_role.ts +23 -0
- package/agent/tools/channel_info.ts +19 -0
- package/agent/tools/create_role.ts +22 -0
- package/agent/tools/list_channels.ts +20 -0
- package/agent/tools/list_guilds.ts +17 -0
- package/agent/tools/list_roles.ts +20 -0
- package/agent/tools/member_detail.ts +20 -0
- package/agent/tools/remove_role.ts +23 -0
- package/lib/endpoint.d.ts +64 -120
- package/lib/endpoint.js +279 -564
- package/lib/index.d.ts +6 -23
- package/lib/index.js +6 -375
- package/lib/platform-permit.d.ts +1 -2
- package/lib/platform-permit.js +4 -2
- package/lib/protocol.d.ts +96 -0
- package/lib/protocol.js +129 -0
- package/lib/qq-agent-deps.d.ts +21 -0
- package/lib/qq-agent-deps.js +30 -0
- package/lib/webhook.d.ts +18 -0
- package/lib/webhook.js +100 -0
- package/lib/ws.d.ts +24 -0
- package/lib/ws.js +118 -0
- package/package.json +47 -33
- package/plugin.ts +13 -0
- package/schema.json +51 -0
- package/src/endpoint.ts +313 -605
- package/src/index.ts +55 -368
- package/src/platform-permit.ts +1 -2
- package/src/protocol.ts +229 -0
- package/src/qq-agent-deps.ts +60 -0
- package/src/webhook.ts +127 -0
- package/src/ws.ts +172 -0
- package/client/Dashboard.tsx +0 -230
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -30
- package/lib/adapter.d.ts +0 -32
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -82
- package/lib/adapter.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/gateway-config.d.ts +0 -14
- package/lib/gateway-config.d.ts.map +0 -1
- package/lib/gateway-config.js +0 -32
- package/lib/gateway-config.js.map +0 -1
- package/lib/group-at-normalize.d.ts +0 -8
- package/lib/group-at-normalize.d.ts.map +0 -1
- package/lib/group-at-normalize.js +0 -68
- package/lib/group-at-normalize.js.map +0 -1
- package/lib/inbound-action.d.ts +0 -15
- package/lib/inbound-action.d.ts.map +0 -1
- package/lib/inbound-action.js +0 -57
- package/lib/inbound-action.js.map +0 -1
- package/lib/inbound-normalize.d.ts +0 -11
- package/lib/inbound-normalize.d.ts.map +0 -1
- package/lib/inbound-normalize.js +0 -47
- package/lib/inbound-normalize.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/mention-enrich.d.ts +0 -12
- package/lib/mention-enrich.d.ts.map +0 -1
- package/lib/mention-enrich.js +0 -52
- package/lib/mention-enrich.js.map +0 -1
- package/lib/outbound-keyboard.d.ts +0 -4
- package/lib/outbound-keyboard.d.ts.map +0 -1
- package/lib/outbound-keyboard.js +0 -96
- package/lib/outbound-keyboard.js.map +0 -1
- package/lib/outbound-markdown.d.ts +0 -24
- package/lib/outbound-markdown.d.ts.map +0 -1
- package/lib/outbound-markdown.js +0 -177
- package/lib/outbound-markdown.js.map +0 -1
- package/lib/outbound-media.d.ts +0 -11
- package/lib/outbound-media.d.ts.map +0 -1
- package/lib/outbound-media.js +0 -51
- package/lib/outbound-media.js.map +0 -1
- package/lib/outbound-mixed-media.d.ts +0 -21
- package/lib/outbound-mixed-media.d.ts.map +0 -1
- package/lib/outbound-mixed-media.js +0 -78
- package/lib/outbound-mixed-media.js.map +0 -1
- package/lib/platform-permit.d.ts.map +0 -1
- package/lib/platform-permit.js.map +0 -1
- package/lib/qq-bind-api.d.ts +0 -37
- package/lib/qq-bind-api.d.ts.map +0 -1
- package/lib/qq-bind-api.js +0 -90
- package/lib/qq-bind-api.js.map +0 -1
- package/lib/qq-bind-flow.d.ts +0 -20
- package/lib/qq-bind-flow.d.ts.map +0 -1
- package/lib/qq-bind-flow.js +0 -86
- package/lib/qq-bind-flow.js.map +0 -1
- package/lib/qq-bind-persist.d.ts +0 -11
- package/lib/qq-bind-persist.d.ts.map +0 -1
- package/lib/qq-bind-persist.js +0 -52
- package/lib/qq-bind-persist.js.map +0 -1
- package/lib/qq-endpoint-manager.d.ts +0 -16
- package/lib/qq-endpoint-manager.d.ts.map +0 -1
- package/lib/qq-endpoint-manager.js +0 -159
- package/lib/qq-endpoint-manager.js.map +0 -1
- package/lib/sdk-version.d.ts +0 -8
- package/lib/sdk-version.d.ts.map +0 -1
- package/lib/sdk-version.js +0 -19
- package/lib/sdk-version.js.map +0 -1
- package/lib/segment-mapper.d.ts +0 -2
- package/lib/segment-mapper.d.ts.map +0 -1
- package/lib/segment-mapper.js +0 -2
- package/lib/segment-mapper.js.map +0 -1
- package/lib/types.d.ts +0 -45
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -101
- package/src/gateway-config.ts +0 -48
- package/src/group-at-normalize.ts +0 -76
- package/src/inbound-action.ts +0 -87
- package/src/inbound-normalize.ts +0 -57
- package/src/mention-enrich.ts +0 -71
- package/src/outbound-keyboard.ts +0 -118
- package/src/outbound-markdown.ts +0 -203
- package/src/outbound-media.ts +0 -58
- package/src/outbound-mixed-media.ts +0 -101
- package/src/qq-bind-api.ts +0 -145
- package/src/qq-bind-flow.ts +0 -127
- package/src/qq-bind-persist.ts +0 -71
- package/src/qq-endpoint-manager.ts +0 -199
- package/src/sdk-version.ts +0 -21
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -53
- /package/{skills/qq → agent}/PERMITS.md +0 -0
- /package/{skills/qq/SKILL.md → agent/skills/qq.md} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @zhin.js/adapter-qq
|
|
2
2
|
|
|
3
|
+
## 5.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cc5c94d: 约定式插件运行时迁移(breaking):插件与适配器由 `usePlugin()` / `extends Adapter` 迁移为 `definePlugin` / `defineAdapter` + `plugin.ts` + 约定目录(`adapters/`、`commands/`、`components/`、`tools/` 等)。
|
|
8
|
+
|
|
9
|
+
- 新增约定式运行时包:`@zhin.js/plugin-runtime`、`@zhin.js/adapter`、`@zhin.js/runtime`、`@zhin.js/host-http`(首版 1.0.0 走 init-publish,不在本 changeset 内 bump)。
|
|
10
|
+
- 全部 20 个平台适配器改为约定式 `defineAdapter`,旧 `usePlugin` / `extends Adapter` / `segment-mapper` 生产入口已删除;onebot11 反向 WSS、onebot12 webhook/wss、milky sse/webhook/wss、satori webhook、kook webhook、qq webhook/middleware 等 slice 1 推迟的连接模式已补齐。
|
|
11
|
+
- 游戏 / 工具 / 服务插件同步迁移到约定目录结构。
|
|
12
|
+
- CLI 增加 plugin-runtime host installer(http/database/outbound/schedule/console 等)。
|
|
13
|
+
|
|
14
|
+
后续加固(同批):
|
|
15
|
+
|
|
16
|
+
- CLI:`zhin runtime start --daemon`(pidfile/崩溃拉起/风暴保护),orphan watchdog 防僵尸进程;legacy `zhin dev` / `zhin start` 已移除(含 `zhin restart`),`zhin stop` 兼容新 daemon。
|
|
17
|
+
- 安全:builtin 工具统一走 `security/policy-facade.ts` 的 `runToolPolicies`(声明式策略表,deny 优先);审计日志 close flush + 背压队列;`splitCompoundCommand` 引号感知、`extractCommandName` 去引号堵绕过。
|
|
18
|
+
- 日志:Logger 双堆栈修复、本地时区、`getLogger` 挂树(`setLevel` 递归生效)、第三方库(log4js/discord)桥接、启动人读总结。
|
|
19
|
+
- 结构:`plugins/games/shared` 迁为 `packages/game-kit`(`@zhin.js/game-kit`);死目录 `plugins/adapters/common` 删除。
|
|
20
|
+
- 脚手架:`create-zhin-app` / `zhin new` / scaffold-wizard 生成物改为 Plugin Runtime 形态(minimal-bot 同构,新配置格式)。
|
|
21
|
+
- Console:endpoint.list 真实名称与 phase、schema:get-all 按 instanceKey 映射、db:\* 接 DatabaseHost。
|
|
22
|
+
|
|
23
|
+
注:按仓库发布惯例(见 1bb345dd2),本次 breaking 迁移统一使用 patch,避免 zhin.js 5.0 级联。
|
|
24
|
+
|
|
25
|
+
- 447f3e2: 迁移缺口修复(legacy 功能对齐):
|
|
26
|
+
|
|
27
|
+
- html 段出站规范化:经 `@zhin.js/html-renderer` 渲染为 image 段(sandbox 豁免、无渲染器时降级文本),修复真实平台 `[object Object]`。
|
|
28
|
+
- 群聊 @ 触发 AI:适配器入站标注 `metadata.mentioned`(icqq/qq/slack/onebot11/onebot12/napcat/milky/discord/telegram/kook/dingtalk/satori),`matchAiTrigger` 补齐 ignorePrefixes/respondToAt/respondToPrivate/keywords(默认值与 legacy 对齐)。
|
|
29
|
+
- im_transcripts 全量流水恢复写入(chat_history 工具可用);群聊旁听上下文回迁。
|
|
30
|
+
- `ai.trigger.timeout/thinkingMessage/errorTemplate` 生效;masters/trusted 角色解析对齐 legacy。
|
|
31
|
+
- `Message.sender` 统一为用户 ID(onebot11/12、napcat、milky 原误传显示名);quote_id 经 metadata 接入 AI 引用上下文。
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [16ec4e8]
|
|
34
|
+
- Updated dependencies [cc5c94d]
|
|
35
|
+
- Updated dependencies [447f3e2]
|
|
36
|
+
- @zhin.js/core@1.3.5
|
|
37
|
+
- @zhin.js/agent@1.0.4
|
|
38
|
+
- @zhin.js/host-http@1.0.1
|
|
39
|
+
- zhin.js@4.1.3
|
|
40
|
+
- @zhin.js/logger@1.0.75
|
|
41
|
+
- @zhin.js/plugin-runtime@1.0.1
|
|
42
|
+
- @zhin.js/adapter@1.0.1
|
|
43
|
+
|
|
44
|
+
## 5.0.2
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- 872c583: Slack 适配器 Phase 1/2:mrkdwn 出站、长消息切分、斜杠/按钮 ephemeral 反馈、入站 mrkdwn→Markdown、editMessage 对齐 core。
|
|
49
|
+
|
|
50
|
+
Logger 表格日志与 string-width 列宽;Agent AI Handler 框线表格与 introspection/MCP 导出;Core side-event 归一化;Schedule 时区规划;多适配器 side-event 与 API surface 更新。
|
|
51
|
+
|
|
52
|
+
- 872c583: fix: 代码格式优化
|
|
53
|
+
- Updated dependencies [872c583]
|
|
54
|
+
- Updated dependencies [872c583]
|
|
55
|
+
- @zhin.js/agent@1.0.3
|
|
56
|
+
- @zhin.js/client@2.0.5
|
|
57
|
+
- @zhin.js/contract@1.0.3
|
|
58
|
+
- @zhin.js/host-api@2.0.5
|
|
59
|
+
- @zhin.js/host-router@2.0.3
|
|
60
|
+
- @zhin.js/logger@1.0.74
|
|
61
|
+
- zhin.js@4.1.2
|
|
62
|
+
|
|
3
63
|
## 5.0.1
|
|
4
64
|
|
|
5
65
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# @zhin.js/adapter-qq
|
|
2
2
|
|
|
3
|
-
Zhin.js QQ
|
|
3
|
+
Zhin.js QQ 官方机器人适配器(Plugin Runtime),默认通过 **WebSocket Gateway**(`qq-official-bot`)收发消息(无需 host-router / host-http)。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- WebSocket Gateway 入站(默认;无需公网 HTTPS / host)
|
|
8
|
+
- 解析私聊 / 群 / 频道消息
|
|
9
|
+
- 出站 `send({ target, payload })` → QQ API(`private:` / `group:` / `channel:` / `direct:`)
|
|
10
|
+
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
11
|
+
- Webhook / middleware 模式已实现(经 `httpHostToken` 注册 POST 路由)
|
|
12
|
+
- AI `@` 触发标注:群消息(GROUP_AT_MESSAGE_CREATE 仅 @ 时下发)与频道 `mentions[].bot` 会在入站 metadata 标 `mentioned: true`(新 Plugin Runtime 纯文本 content 经 metadata 传递 @)
|
|
4
13
|
|
|
5
14
|
## 安装
|
|
6
15
|
|
|
@@ -8,434 +17,69 @@ Zhin.js QQ 官方机器人适配器,基于 QQ 官方机器人 API 开发,支
|
|
|
8
17
|
pnpm add @zhin.js/adapter-qq
|
|
9
18
|
```
|
|
10
19
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
无需手动复制 AppID/AppSecret:在 IM 中由 **master / trusted** 操作员发送命令,适配器会内联调用 QQ 开放平台绑定协议(等价 `@tencent-connect/qqbot-connector`,**不依赖**该 npm 包),扫码成功后:
|
|
14
|
-
|
|
15
|
-
- 凭据写入项目根 **`.env`**(键名 `QQ_<name>_APPID` / `QQ_<name>_SECRET`)
|
|
16
|
-
- `zhin.config.yml` 仅保留 **`${...}` 引用**(与脚手架其它 adapter 一致)
|
|
17
|
-
- **`master`** 与 **`aiAccess.users`** 自动设为 `poll_bind_result` 返回的扫码者 OpenID(接口无该字段时回退为发起命令的用户 ID)
|
|
18
|
-
|
|
19
|
-
| 命令 | 说明 |
|
|
20
|
-
|------|------|
|
|
21
|
-
| `/endpoint add qq [name]` | 发起扫码绑定;`name` 默认使用 AppID |
|
|
22
|
-
| `/endpoint sync` | 将内存 endpoint 写回 `zhin.config.yml` |
|
|
23
|
-
| `/endpoint cancel` | 取消进行中的绑定 |
|
|
24
|
-
| `/endpoints` | 查看运行时 qq endpoints 在线状态 |
|
|
25
|
-
| `/endpoint help` | Endpoint 管理帮助 |
|
|
26
|
-
|
|
27
|
-
二维码通过 IM `$reply` 发送 `segment.qrcode(url)`;各 Adapter 在 **`$sendMessage`** 内解析该段(IM → `image`,process → 终端 ASCII,GitHub 等 → 文本链接)。
|
|
28
|
-
|
|
29
|
-
二维码渲染使用 core 的 `segment.qrcode` / `GeneratedQrCode`(`import { segment } from 'zhin.js'` 或 `import { GeneratedQrCode } from 'zhin.js/qrcode'`)。
|
|
30
|
-
|
|
31
|
-
## AIGC 合规(AI 白名单)
|
|
32
|
-
|
|
33
|
-
QQ 开放平台限制 AIGC 进入社群场景、禁止面向全量用户开放生成式能力。请配置 **`endpoints[].aiAccess`**(推荐)或全局 **`ai.access`**,仅 gate LLM 回复;斜杠命令、游戏插件等不受影响。
|
|
34
|
-
|
|
35
|
-
```yaml
|
|
36
|
-
endpoints:
|
|
37
|
-
- context: qq
|
|
38
|
-
name: my-bot
|
|
39
|
-
appid: ...
|
|
40
|
-
secret: ...
|
|
41
|
-
aiAccess:
|
|
42
|
-
mode: whitelist
|
|
43
|
-
users: ['QQ用户openid']
|
|
44
|
-
groups: ['QQ群openid']
|
|
45
|
-
denyMessage: 当前未开放 AI,请联系管理员。
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
多 Endpoint 时可分别设置(例如正式服 `whitelist`、沙箱 `open`)。未写 `endpoints[].aiAccess` 时回退到全局 `ai.access`。
|
|
20
|
+
## Plugin Runtime
|
|
49
21
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
22
|
+
- `@zhin.js/adapter` — 约定式 `adapters/qq.ts`(`defineAdapter`)
|
|
23
|
+
- `@zhin.js/core` — `messageGatewayToken` 入站/出站
|
|
24
|
+
- `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
|
|
25
|
+
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
26
|
+
- **无需** `@zhin.js/host-http` / `@zhin.js/host-router`(WebSocket 路径)
|
|
53
27
|
|
|
54
|
-
|
|
28
|
+
入站:`gateway.receive({ adapter, target: 'group:…'|…, content, sender, metadata })`
|
|
29
|
+
出站:`send({ target, payload })` → `sendPrivateMessage` / `sendGroupMessage` / `sendGuildMessage`
|
|
55
30
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
### 基础配置
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { defineConfig } from 'zhin.js';
|
|
62
|
-
|
|
63
|
-
export default defineConfig({
|
|
64
|
-
endpoints: [
|
|
65
|
-
{
|
|
66
|
-
context: 'qq',
|
|
67
|
-
name: 'my-qq-bot',
|
|
68
|
-
appid: process.env.QQ_APPID,
|
|
69
|
-
secret: process.env.QQ_SECRET,
|
|
70
|
-
mode: 'middleware',
|
|
71
|
-
application: 'koa',
|
|
72
|
-
webhookPath: '/qq/webhook',
|
|
73
|
-
sandbox: true,
|
|
74
|
-
data_dir: './data',
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
plugins: [
|
|
78
|
-
'@zhin.js/adapter-qq',
|
|
79
|
-
],
|
|
80
|
-
})
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### 完整配置选项
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
const config: QQEndpointConfig = {
|
|
87
|
-
context: 'qq',
|
|
88
|
-
name: 'my-qq-bot',
|
|
89
|
-
appid: 'YOUR_APPID', // 机器人 AppID(必需,小写 appid)
|
|
90
|
-
secret: 'YOUR_SECRET', // 机器人 Secret(必需)
|
|
91
|
-
mode: 'middleware', // websocket | webhook | middleware(推荐挂 host-router)
|
|
92
|
-
application: 'koa', // middleware 模式必填
|
|
93
|
-
webhookPath: '/qq/webhook', // middleware 回调路径(完整 URL: {host}:8086/qq/webhook,无 /api 前缀)
|
|
94
|
-
// mode: 'webhook', // 独立 HTTP 端口模式
|
|
95
|
-
// port: 8087,
|
|
96
|
-
// path: '/qq/webhook',
|
|
97
|
-
platform: 'qq', // 'qq' | 'qzone' 平台类型
|
|
98
|
-
intents: [ // 事件订阅意图(qq-official-bot ^1.2 使用 GROUP_AND_C2C_EVENT)
|
|
99
|
-
'GROUP_AND_C2C_EVENT', // QQ 群 @ 消息 + C2C 私聊(必需)
|
|
100
|
-
'GUILDS',
|
|
101
|
-
'GUILD_MEMBERS',
|
|
102
|
-
'GUILD_MESSAGES', // 频道私域 @ 消息(公域用 PUBLIC_GUILD_MESSAGES)
|
|
103
|
-
'DIRECT_MESSAGE',
|
|
104
|
-
'PUBLIC_GUILD_MESSAGES',
|
|
105
|
-
],
|
|
106
|
-
data_dir: './data', // 数据目录(可选)
|
|
107
|
-
sandbox: false // 是否为沙箱环境(可选)
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## 入站模式(二选一)
|
|
112
|
-
|
|
113
|
-
| 模式 | 配置 | 说明 |
|
|
114
|
-
|------|------|------|
|
|
115
|
-
| **middleware**(推荐) | `mode: middleware` + `application: koa` + `webhookPath` | 挂在 `@zhin.js/host-router`,与 Host **同端口**(如 `8086`) |
|
|
116
|
-
| **webhook**(独立端口) | `mode: webhook` + `port` + `path` | `qq-official-bot` 自建 HTTP 服务,需单独暴露端口 |
|
|
117
|
-
| websocket | `mode: websocket` | 长连接,无需公网回调 |
|
|
118
|
-
|
|
119
|
-
### 自定义网关(qq-official-bot ^1.2.2)
|
|
120
|
-
|
|
121
|
-
经代理或私有部署时,可覆盖官方 token / gateway 接口:
|
|
122
|
-
|
|
123
|
-
```yaml
|
|
124
|
-
# WebSocket 入站:gatewayUrl 与 accessTokenUrl 均生效
|
|
125
|
-
- context: qq
|
|
126
|
-
name: my-qq-bot
|
|
127
|
-
mode: websocket
|
|
128
|
-
appid: ${QQ_APPID}
|
|
129
|
-
secret: ${QQ_SECRET}
|
|
130
|
-
accessTokenUrl: https://your-proxy.example.com/app/getAppAccessToken
|
|
131
|
-
gatewayUrl: https://your-proxy.example.com/gateway/bot
|
|
132
|
-
intents:
|
|
133
|
-
- GROUP_AND_C2C_EVENT
|
|
134
|
-
```
|
|
31
|
+
## 前置条件
|
|
135
32
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
application: koa
|
|
142
|
-
webhookPath: /qq/webhook
|
|
143
|
-
accessTokenUrl: https://your-proxy.example.com/app/getAppAccessToken
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
- `gatewayUrl` 可为完整 URL 或相对路径(默认 `/gateway/bot`,相对 `api.sgroup.qq.com` baseURL)
|
|
147
|
-
- 连接时日志会输出 `op: qq_gateway` 及实际使用的地址
|
|
148
|
-
|
|
149
|
-
### middleware 回调地址(test-bot 默认)
|
|
150
|
-
|
|
151
|
-
1. 确保 `plugins` 含 `@zhin.js/host-router`(test-bot 已启用)
|
|
152
|
-
2. `zhin.config.yml` 示例见上文 `webhookPath: /qq/webhook`
|
|
153
|
-
3. 在 [QQ 开放平台](https://q.qq.com/bot) → **开发 → 回调配置** 填写:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
https://<你的公网域名>/qq/webhook
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
本地:`http://127.0.0.1:8086/qq/webhook`(经 ngrok / cloudflared 暴露公网即可)。
|
|
160
|
-
|
|
161
|
-
> **注意**:Host 的 Console/API 走 `/api/*`(如 `/api/stats`),但适配器 webhook 直接挂在 Router 根路径,**不要**加 `/api` 前缀;填 `/api/qq/webhook` 会命中 Bearer 鉴权,QQ 平台回调会 401。
|
|
162
|
-
|
|
163
|
-
4. 勾选事件:**群事件**、**C2C 私聊**、**频道事件**(按需)
|
|
164
|
-
5. 保存时平台会发 `SIGN_VERIFY` 签名校验,适配器会自动响应
|
|
165
|
-
|
|
166
|
-
> Host 对含 `/webhook` 的路径**免 Bearer 鉴权**,由 QQ 的 `X-Signature-Ed25519` 验签。
|
|
167
|
-
|
|
168
|
-
### webhook 独立端口
|
|
169
|
-
|
|
170
|
-
```yaml
|
|
171
|
-
mode: webhook
|
|
172
|
-
port: 8087
|
|
173
|
-
path: /qq/webhook
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
回调填 `https://<域名>:8087/qq/webhook`(或反代到该端口)。
|
|
177
|
-
|
|
178
|
-
## 获取配置信息
|
|
179
|
-
|
|
180
|
-
### 1. 注册 QQ 机器人
|
|
181
|
-
|
|
182
|
-
1. 访问 [QQ 开放平台](https://q.qq.com/bot)
|
|
183
|
-
2. 登录并创建机器人应用
|
|
184
|
-
3. 在「开发设置」中获取:
|
|
185
|
-
- **AppID**(配置字段 `appid`): 机器人应用 ID
|
|
186
|
-
- **Secret**: 机器人密钥(`secret`)
|
|
187
|
-
- **Secret**: 机器人密钥
|
|
188
|
-
|
|
189
|
-
### 2. 配置权限
|
|
190
|
-
|
|
191
|
-
在机器人设置中:
|
|
192
|
-
- 配置需要的事件订阅
|
|
193
|
-
- 设置消息接收模式(公域/私域)
|
|
194
|
-
- 添加频道/群聊白名单(如需要)
|
|
195
|
-
|
|
196
|
-
### 3. 事件订阅(Intents)
|
|
197
|
-
|
|
198
|
-
可订阅的事件类型:
|
|
199
|
-
- `GUILDS` - 频道事件
|
|
200
|
-
- `GUILD_MEMBERS` - 成员变动
|
|
201
|
-
- `GUILD_MESSAGES` - 频道消息
|
|
202
|
-
- `DIRECT_MESSAGE` - 私信消息
|
|
203
|
-
- `GROUP_AND_C2C_EVENT` - QQ 群 @ 消息 + C2C 私聊(`GROUP_AT_MESSAGE_CREATE` / `C2C_MESSAGE_CREATE`)
|
|
204
|
-
- `INTERACTION` - 互动事件
|
|
205
|
-
|
|
206
|
-
## 使用示例
|
|
207
|
-
|
|
208
|
-
### 基础消息处理
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
import { addCommand, MessageCommand } from 'zhin.js'
|
|
212
|
-
|
|
213
|
-
addCommand(new MessageCommand('hello <name:text>')
|
|
214
|
-
.action(async (message, result) => {
|
|
215
|
-
return `你好,${result.params.name}!`
|
|
216
|
-
})
|
|
217
|
-
)
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### 频道消息
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import { onMessage } from 'zhin.js'
|
|
224
|
-
|
|
225
|
-
onMessage(async (message) => {
|
|
226
|
-
// 仅处理频道消息
|
|
227
|
-
if (message.$channel.type === 'channel') {
|
|
228
|
-
console.log(`频道消息:${message.$raw}`)
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### 群聊消息
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
import { onGroupMessage } from 'zhin.js'
|
|
237
|
-
|
|
238
|
-
onGroupMessage(async (message) => {
|
|
239
|
-
console.log(`群聊消息来自:${message.$sender.name}`)
|
|
240
|
-
console.log(`消息内容:${message.$raw}`)
|
|
241
|
-
})
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### 私聊消息
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
import { onPrivateMessage } from 'zhin.js'
|
|
248
|
-
|
|
249
|
-
onPrivateMessage(async (message) => {
|
|
250
|
-
await message.$reply('收到你的私信了!')
|
|
251
|
-
})
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### 发送不同类型消息
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
addCommand(new MessageCommand('card')
|
|
258
|
-
.action(async (message) => {
|
|
259
|
-
// 发送 Ark 模板卡片
|
|
260
|
-
return {
|
|
261
|
-
type: 'ark',
|
|
262
|
-
template_id: 23,
|
|
263
|
-
kv: [
|
|
264
|
-
{ key: '#TITLE#', value: '标题' },
|
|
265
|
-
{ key: '#DESC#', value: '描述' },
|
|
266
|
-
{ key: '#PROMPT#', value: '提示' }
|
|
267
|
-
]
|
|
268
|
-
}
|
|
269
|
-
})
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
addCommand(new MessageCommand('embed')
|
|
273
|
-
.action(async (message) => {
|
|
274
|
-
// 发送 Embed 消息
|
|
275
|
-
return {
|
|
276
|
-
type: 'embed',
|
|
277
|
-
title: 'Embed 标题',
|
|
278
|
-
prompt: '消息提示',
|
|
279
|
-
thumbnail: { url: 'https://example.com/image.png' },
|
|
280
|
-
fields: [
|
|
281
|
-
{ name: '字段1', value: '值1' }
|
|
282
|
-
]
|
|
283
|
-
}
|
|
284
|
-
})
|
|
285
|
-
)
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## 消息类型支持
|
|
289
|
-
|
|
290
|
-
### 接收消息类型
|
|
291
|
-
|
|
292
|
-
- ✅ 文本消息
|
|
293
|
-
- ✅ @ 提及
|
|
294
|
-
- ✅ 图片消息
|
|
295
|
-
- ✅ 表情消息
|
|
296
|
-
- ✅ Ark 模板消息
|
|
297
|
-
- ✅ Embed 消息
|
|
298
|
-
- ✅ Markdown 消息
|
|
299
|
-
|
|
300
|
-
### 发送消息类型
|
|
301
|
-
|
|
302
|
-
- ✅ 文本消息
|
|
303
|
-
- ✅ 图片消息
|
|
304
|
-
- ✅ Ark 模板消息
|
|
305
|
-
- ✅ Embed 富文本消息
|
|
306
|
-
- ✅ Markdown 消息
|
|
307
|
-
- ✅ 消息引用(回复)
|
|
308
|
-
|
|
309
|
-
### AI 出站 Markdown(默认开启)
|
|
33
|
+
| 要求 | 说明 |
|
|
34
|
+
|------|------|
|
|
35
|
+
| **AppID / Secret** | [QQ 开放平台](https://q.qq.com/) 创建机器人应用并获取 |
|
|
36
|
+
| **WebSocket(默认)** | `qq-official-bot` 正向连接;无需公网回调 |
|
|
37
|
+
| **host-http** | WebSocket **不需要**;Webhook / middleware 模式需要(经 `httpHostToken`) |
|
|
310
38
|
|
|
311
|
-
|
|
39
|
+
必填字段:`appid`、`secret`。
|
|
312
40
|
|
|
313
|
-
|
|
314
|
-
|---|---|
|
|
315
|
-
| `auto`(默认) | 正文含 `**`、列表、代码块等 Markdown 语法时才转换 |
|
|
316
|
-
| `true` | 纯文本也走 Markdown |
|
|
317
|
-
| `false` | 始终发纯文本(与旧行为一致) |
|
|
41
|
+
## 最小配置
|
|
318
42
|
|
|
319
43
|
```yaml
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
**图文混排**(文本 + 图片,典型如二维码说明 + `segment.qrcode`)会自动处理:
|
|
329
|
-
|
|
330
|
-
| 图片类型 | 行为 |
|
|
331
|
-
|---|---|
|
|
332
|
-
| 公网 `https` URL | 合并为单条 Markdown(`msg_type=2`),图片用 `` |
|
|
333
|
-
| 内联 base64 / data URI(如二维码渲染) | 群聊/私聊先上传 `file_info`,再以 `msg_type=7` 图文混排同条发送 |
|
|
334
|
-
|
|
335
|
-
`outboundMarkdown: false` 时关闭上述合并,恢复分条发送。
|
|
336
|
-
|
|
337
|
-
## API 方法
|
|
338
|
-
|
|
339
|
-
### 基础方法
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
const endpoint = app.adapters.get('qq')?.endpoints.get('你的机器人ID')
|
|
343
|
-
|
|
344
|
-
// 发送私信
|
|
345
|
-
await endpoint.sendPrivateMessage(userId, '消息内容')
|
|
346
|
-
|
|
347
|
-
// 发送群消息
|
|
348
|
-
await endpoint.sendGroupMessage(groupId, '消息内容')
|
|
349
|
-
|
|
350
|
-
// 发送频道消息
|
|
351
|
-
await endpoint.sendGuildMessage(channelId, '消息内容')
|
|
352
|
-
|
|
353
|
-
// 撤回消息
|
|
354
|
-
await endpoint.$recallMessage(messageId)
|
|
44
|
+
# zhin.config.yml(Plugin Runtime)
|
|
45
|
+
plugins:
|
|
46
|
+
qq:
|
|
47
|
+
name: my-qq-bot
|
|
48
|
+
appid: ${QQ_APPID}
|
|
49
|
+
secret: ${QQ_SECRET}
|
|
50
|
+
# mode: websocket # 默认
|
|
355
51
|
```
|
|
356
52
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
本适配器使用特殊的消息 ID 格式来区分不同类型的消息:
|
|
360
|
-
|
|
361
|
-
- 私信:`private-{userId}:{messageId}`
|
|
362
|
-
- 群聊:`group-{groupId}:{messageId}`
|
|
363
|
-
- 频道:`channel-{channelId}:{messageId}`
|
|
364
|
-
- 私域频道:`direct-{guildId}:{messageId}`
|
|
365
|
-
|
|
366
|
-
## 注意事项
|
|
367
|
-
|
|
368
|
-
### 接收模式
|
|
369
|
-
|
|
370
|
-
- **公域模式 (public)**: 仅接收 @ 机器人的消息
|
|
371
|
-
- **私域模式 (private)**: 可接收频道内所有消息(需要申请权限)
|
|
372
|
-
|
|
373
|
-
### 频率限制
|
|
53
|
+
根插件 `zhin.plugins`(或项目图)需引用 `@zhin.js/adapter-qq`(`instanceKey: qq`)。
|
|
374
54
|
|
|
375
|
-
|
|
376
|
-
- 主动消息:每个用户每天 5 条
|
|
377
|
-
- 被动消息(回复):无限制
|
|
378
|
-
- 建议在被动模式下使用(用户 @ 后回复)
|
|
55
|
+
## 环境变量
|
|
379
56
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
{
|
|
386
|
-
context: 'qq',
|
|
387
|
-
sandbox: true, // 启用沙箱
|
|
388
|
-
// ...其他配置
|
|
389
|
-
}
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
## 常见问题
|
|
393
|
-
|
|
394
|
-
### Q: 机器人无法收到消息?
|
|
395
|
-
|
|
396
|
-
A: 检查以下几点:
|
|
397
|
-
1. AppID、Secret 是否正确;`intents` 必须含 **`GROUP_AND_C2C_EVENT`**(不是旧名 `GROUP_AT_MESSAGE_CREATE`)
|
|
398
|
-
2. **沙箱环境**:在 [QQ 开放平台](https://q.qq.com/bot) → 开发设置 → 沙箱配置,把测试 **QQ 群** 加入沙箱白名单(私聊能通不代表群已配置)
|
|
399
|
-
3. 机器人是否已被拉入该 QQ 群(日志应出现 `qq notice group.add_robot`)
|
|
400
|
-
4. 群管理员是否在机器人资料页 **开启消息接收**(`qq notice group.msg_receive_open`);若出现 `group.msg_receive_close` 则群聊不会推送
|
|
401
|
-
5. 公域/群聊场景必须 **@ 机器人** 才会推送(`GROUP_AT_MESSAGE_CREATE`)
|
|
402
|
-
6. **QQ 频道** 与 **QQ 群** 是两套事件:频道 @ 需要 `GUILD_MESSAGES` 或 `PUBLIC_GUILD_MESSAGES`,不是 `GROUP_AND_C2C_EVENT`
|
|
403
|
-
|
|
404
|
-
### Q: Typing Indicator 群聊报 `40034105 主动消息失败, 无权限`?
|
|
57
|
+
| 变量 | 说明 |
|
|
58
|
+
|------|------|
|
|
59
|
+
| `QQ_APPID` / `QQ_BOT_APPID` | 应用 AppID |
|
|
60
|
+
| `QQ_SECRET` / `QQ_BOT_SECRET` | 应用 Secret |
|
|
61
|
+
| `QQ_BOT_NAME` | 可选,默认 endpoint 名 |
|
|
405
62
|
|
|
406
|
-
|
|
63
|
+
## Webhook / middleware
|
|
407
64
|
|
|
408
|
-
|
|
409
|
-
typingIndicator:
|
|
410
|
-
enabled: true
|
|
411
|
-
groupConfig:
|
|
412
|
-
type: none
|
|
413
|
-
```
|
|
65
|
+
`mode: webhook` 或 `mode: middleware` 经 `httpHostToken` 注册 POST 路由(默认 `/qq/webhook`),使用 qq-official-bot Middleware 接收器验签并入站;出站仍走 QQ HTTP API。Host 需注入 `httpHostToken`。
|
|
414
66
|
|
|
415
|
-
|
|
67
|
+
## AI 工具(Skill)
|
|
416
68
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
69
|
+
| 类别 | 路径 |
|
|
70
|
+
|------|------|
|
|
71
|
+
| Permit 词汇 | `agent/PERMITS.md` |
|
|
72
|
+
| 平台工具 | `agent/tools/`(频道、角色等) |
|
|
73
|
+
| 技能说明 | `agent/skills/qq.md` |
|
|
422
74
|
|
|
423
|
-
|
|
75
|
+
## 平台权限(platform permit)
|
|
424
76
|
|
|
425
|
-
|
|
426
|
-
- `qq`: QQ 频道和群聊
|
|
427
|
-
- `qzone`: QQ 空间(如支持)
|
|
77
|
+
platform permit checker 由 `plugin.ts` 的 generation 生命周期注册;`@zhin.js/tool` descriptor 保留 `platforms` / `scopes` / `permissions`,CapabilityIngress 与 ToolSystem 统一经 Core `canAccessTool()` 执行门禁。
|
|
428
78
|
|
|
429
|
-
##
|
|
79
|
+
## 迁移后出站能力变化
|
|
430
80
|
|
|
431
|
-
|
|
432
|
-
- [QQ 机器人开发文档](https://bot.q.qq.com/wiki/)
|
|
433
|
-
- [Zhin.js 官方文档](https://github.com/zhinjs/zhin)
|
|
81
|
+
迁移到 Plugin Runtime 后,出站统一经 `messageGatewayToken` 渲染为文本后发送(`sendPrivateMessage` / `sendGroupMessage` / `sendGuildMessage`)。旧 Adapter 的富媒体出站能力(图片 / 语音 / 视频、keyboard 按钮、markdown 模板等)暂未迁移,当前出站等价于纯文本。如需富媒体,可通过 endpoint 的 QQ API 封装或直接调用 QQ HTTP API 作为逃生舱。
|
|
434
82
|
|
|
435
83
|
## 许可证
|
|
436
84
|
|
|
437
85
|
MIT License
|
|
438
|
-
|
|
439
|
-
## 贡献
|
|
440
|
-
|
|
441
|
-
欢迎提交 Issue 和 Pull Request!
|
package/adapters/qq.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convention entry: discover `adapters/qq.ts` → defineAdapter.
|
|
3
|
+
*/
|
|
4
|
+
import { defineAdapter } from '@zhin.js/adapter';
|
|
5
|
+
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
6
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
7
|
+
import { QqHttpEndpoint, QqWebsocketEndpoint } from '../src/endpoint.js';
|
|
8
|
+
import {
|
|
9
|
+
resolveQqConfig,
|
|
10
|
+
type QqAdapterConfig,
|
|
11
|
+
} from '../src/protocol.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
QqHttpEndpoint,
|
|
15
|
+
QqWebsocketEndpoint,
|
|
16
|
+
} from '../src/endpoint.js';
|
|
17
|
+
export type {
|
|
18
|
+
CreateQqBot,
|
|
19
|
+
CreateQqHttpBot,
|
|
20
|
+
QqBotTransport,
|
|
21
|
+
QqEndpointOptions,
|
|
22
|
+
QqHttpBotTransport,
|
|
23
|
+
QqHttpEndpointOptions,
|
|
24
|
+
} from '../src/endpoint.js';
|
|
25
|
+
|
|
26
|
+
export default defineAdapter<QqAdapterConfig>({
|
|
27
|
+
capabilities: ['inbound', 'outbound'],
|
|
28
|
+
create(context) {
|
|
29
|
+
const config = resolveQqConfig(context.config);
|
|
30
|
+
const gateway = context.use(messageGatewayToken);
|
|
31
|
+
if (config.mode === 'webhook' || config.mode === 'middleware') {
|
|
32
|
+
return new QqHttpEndpoint({
|
|
33
|
+
id: context.id,
|
|
34
|
+
gateway,
|
|
35
|
+
http: context.use(httpHostToken),
|
|
36
|
+
config,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return new QqWebsocketEndpoint({
|
|
40
|
+
id: context.id,
|
|
41
|
+
gateway,
|
|
42
|
+
config,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { platformPermit } from '../../src/platform-permit.js';
|
|
4
|
+
import { getQqAgentDeps } from '../../src/qq-agent-deps.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool<{ endpoint_id: string; guild_id: string; channel_id: string; user_id: string; role_id: string }>({
|
|
7
|
+
description: '给成员添加 QQ 频道角色',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
|
+
guild_id: z.string().describe('频道 ID'),
|
|
11
|
+
channel_id: z.string().describe('子频道 ID'),
|
|
12
|
+
user_id: z.string().describe('用户 ID'),
|
|
13
|
+
role_id: z.string().describe('角色 ID'),
|
|
14
|
+
}),
|
|
15
|
+
platforms: ['qq'],
|
|
16
|
+
tags: ['qq'],
|
|
17
|
+
permissions: [platformPermit('manage_roles')],
|
|
18
|
+
async execute({ endpoint_id, guild_id, channel_id, user_id, role_id }: { endpoint_id: string; guild_id: string; channel_id: string; user_id: string; role_id: string }) {
|
|
19
|
+
const endpoint = getQqAgentDeps().getEndpoint(endpoint_id);
|
|
20
|
+
const success = await endpoint.addMemberRole(guild_id, channel_id, user_id, role_id);
|
|
21
|
+
return { success, message: success ? '已给成员添加角色' : '操作失败' };
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { platformPermit } from '../../src/platform-permit.js';
|
|
4
|
+
import { getQqAgentDeps } from '../../src/qq-agent-deps.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool<{ endpoint_id: string; channel_id: string }>({
|
|
7
|
+
description: '获取 QQ 频道中指定子频道的详细信息',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
|
+
channel_id: z.string().describe('子频道 ID'),
|
|
11
|
+
}),
|
|
12
|
+
platforms: ['qq'],
|
|
13
|
+
tags: ['qq'],
|
|
14
|
+
permissions: [platformPermit('guild_admin')],
|
|
15
|
+
async execute({ endpoint_id, channel_id }: { endpoint_id: string; channel_id: string }) {
|
|
16
|
+
const endpoint = getQqAgentDeps().getEndpoint(endpoint_id);
|
|
17
|
+
return endpoint.getChannelInfo(channel_id);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { platformPermit } from '../../src/platform-permit.js';
|
|
4
|
+
import { getQqAgentDeps } from '../../src/qq-agent-deps.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool<{ endpoint_id: string; guild_id: string; name: string; color?: number }>({
|
|
7
|
+
description: '创建 QQ 频道角色',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
|
+
guild_id: z.string().describe('频道 ID'),
|
|
11
|
+
name: z.string().describe('角色名称'),
|
|
12
|
+
color: z.number().optional().describe('颜色(RGB 十进制数值)'),
|
|
13
|
+
}),
|
|
14
|
+
platforms: ['qq'],
|
|
15
|
+
tags: ['qq'],
|
|
16
|
+
permissions: [platformPermit('guild_owner')],
|
|
17
|
+
async execute({ endpoint_id, guild_id, name, color }: { endpoint_id: string; guild_id: string; name: string; color?: number }) {
|
|
18
|
+
const endpoint = getQqAgentDeps().getEndpoint(endpoint_id);
|
|
19
|
+
const role = await endpoint.createGuildRole(guild_id, name, color);
|
|
20
|
+
return { success: !!role, role, message: role ? `角色 "${name}" 创建成功` : '创建失败' };
|
|
21
|
+
},
|
|
22
|
+
});
|